/*
 * File:   WorkThread.h
 * Author: lizb
 */

_Pragma("once");

#include <thread>
#include <memory>
#include <cassert>


template<class WORKABLE>
class WorkThread {
public:
    typedef WORKABLE Workable;

    WorkThread(void);
    ~WorkThread(void);

    WORKABLE* setWorkable(WORKABLE* pWorkable) {
        WORKABLE* pTempWorkable = mpWorkable;
        mpWorkable = pWorkable;

        return pTempWorkable;
    }

    bool isRunning(void) {
        bool result = false;
        if (!mrealStopped && mrun) {
            result = true;
        } else {
            result = false;
        }
        return result;
    }

    bool start(void);
    bool stop(const bool join = false);

    void setAutoDelete(const bool autoDelete) {
        mautoDelete = autoDelete;
    }

    void join() {
        if (mthread && mthread->joinable()) {
            mthread->join();
            // pthread_join(mthread, NULL);
        }
    }

protected:
    void run(void);

    static void* nativeThreadRoute(void* opaque = nullptr);

private:
    WORKABLE*           mpWorkable;
    std::unique_ptr<std::thread>         mthread;
    volatile bool       mrun;  //outside command flag to control the thread running.
    volatile bool       mrealStopped;
    volatile bool       mautoDelete;
};


template<class WORKABLE>
void* WorkThread<WORKABLE>::nativeThreadRoute(void* opaque) {
    assert(NULL != opaque);
    ((WorkThread*)opaque)->run();

    return 0;
}


template<class WORKABLE>
WorkThread<WORKABLE>::WorkThread(void) : mpWorkable(NULL), mrun(false), mrealStopped(true), mautoDelete(false) {
}


template<class WORKABLE>
WorkThread<WORKABLE>::~WorkThread(void) {
}


template<class WORKABLE>
bool WorkThread<WORKABLE>::start(void) {
    mrun = true;
    //  int result = pthread_create(&mthread, NULL, nativeThreadRoute, this);
    //assert(("error on create thread", 0 == result));
    mthread.reset(new std::thread(nativeThreadRoute, this));
//    if (mautoDelete) {
//        mthread->detach();
//    }
    return true;
}


template<class WORKABLE>
bool WorkThread<WORKABLE>::stop(bool bjoin) {
    mrun = false;
    /* assert(NULL != mthread);
     if (NULL == mthread)
     {
         return true;
     }
     */
    if (bjoin) {
        join();
    }
    return true;
}


template<class WORKABLE>
void WorkThread<WORKABLE>::run(void) {
    mrealStopped = false;
    bool result(true);
    assert(NULL != mpWorkable);
    if (NULL == mpWorkable) {
        goto end;
    }
    result = mpWorkable->initial();
    assert(result);
    if (!result) {
        goto end;
    }

    while (mrun) {
        mpWorkable->doWork();
    }
    result = mpWorkable->uninitial();
    assert(result);

end:
    mrealStopped = true; //this statement is must be the last in this function.
    if (mautoDelete) {
        mthread->detach();
        delete mpWorkable;
    }
}

